using System;
using System.Numerics;
namespace Meow.Core;

public readonly struct int3 : IEquatable<int3>
{
	public readonly int X, Y, Z;
	public int3(int x, int y, int z) { X = x; Y = y; Z = z; }

	public static int3 operator +(int3 a, int3 b) { return new int3(a.X + b.X, a.Y + b.Y, a.Z + b.Z); }
	public static int3 operator -(int3 a, int3 b) { return new int3(a.X - b.X, a.Y - b.Y, a.Z - b.Z); }
	public static int3 operator *(int a, int3 b) { return new int3(a * b.X, a * b.Y, a * b.Z); }
	public static int3 operator *(int3 b, int a) { return new int3(a * b.X, a * b.Y, a * b.Z); }
	public static int3 operator /(int3 a, int b) { return new int3(a.X / b, a.Y / b, a.Z / b); }

	public static int3 operator -(int3 a) { return new int3(-a.X, -a.Y, -a.Z); }

	public static bool operator ==(int3 me, int3 other) { return me.X == other.X && me.Y == other.Y && me.Z == other.Z; }
	public static bool operator !=(int3 me, int3 other) { return !(me == other); }

	public override int GetHashCode() { return X.GetHashCode() ^ Y.GetHashCode() ^ Z.GetHashCode(); }

	public bool Equals(int3 other) { return this == other; }
	public override bool Equals(object obj) { return obj is int3 vec && Equals(vec); }

	public override string ToString() { return X + "," + Y + "," + Z; }

	public int3 Sign() { return new int3(Math.Sign(X), Math.Sign(Y), Math.Sign(Z)); }
	public int3 Abs() { return new int3(Math.Abs(X), Math.Abs(Y), Math.Abs(Z)); }
	public int LengthSquared => X * X + Y * Y + Z * Z;
	public int Length => Exts.ISqrt(LengthSquared);

	public int3 WithX(int newX)
	{
		return new int3(newX, Y, Z);
	}

	public int3 WithY(int newY)
	{
		return new int3(X, newY, Z);
	}

    public int3 WithZ(int newZ)
    {
        return new int3(X, Y, newZ);
    }

    public static int3 Max(int3 a, int3 b) { return new int3(Math.Max(a.X, b.X), Math.Max(a.Y, b.Y), Math.Max(a.Z, b.Z)); }
	public static int3 Min(int3 a, int3 b) { return new int3(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y), Math.Min(a.Z, b.Z)); }

	public static readonly int3 Zero = new int3(0, 0, 0);
	public Vector2 ToVector2() { return new Vector2(X, Y); }
	public Vector3 ToVector3() { return new Vector3(X, Y, Z); }

	public static int3 FromVector2(Vector2 vec2) { return new int3((int)vec2.X, (int)vec2.Y, 0); }
	public static int3 FromVector3(Vector3 vec3) { return new int3((int)vec3.X, (int)vec3.Y, (int)vec3.Z); }

	public static int3 Lerp(int3 a, int3 b, int mul, int div)
	{
		return a + (b - a) * mul / div;
	}

	public static int Dot(int3 a, int3 b) { return a.X * b.X + a.Y * b.Y + a.Z * b.Z; }
}
